package com.dosgi;

import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.dosgi.bean.BeanFactoryDefault;
import com.dosgi.bean.IBeanFactory;
import com.dosgi.clazz.ClassHandler;
import com.dosgi.kit.StrKit;
import com.dosgi.module.IModuleContext;

/**
 * 默认应用上下文
 * 
 * @author dingnate
 *
 */
public class DosgiContextDefault implements IDosgiContext {
	private static transient final Logger LOG = LoggerFactory
			.getLogger(DosgiContextDefault.class);
	/**
	 * bean工厂
	 */
	private IBeanFactory beanFactory = new BeanFactoryDefault();

	private HashMap<String, TreeSet<IModuleContext>> symbolicName2modules = new HashMap<String, TreeSet<IModuleContext>>();
	private HashMap<String, TreeSet<IModuleContext>> exportPackage2Modules = new HashMap<String, TreeSet<IModuleContext>>();
	private HashSet<ClassHandler> classHandlers = new HashSet<ClassHandler>();
	private Comparator<IModuleContext> mVerReverseComparator = Collections
			.reverseOrder(getModuleContextVersionComparator());

	@Override
	public IDosgiContext start() throws Throwable {
		return this;
	}

	/**
	 * 上下文销毁
	 */
	@Override
	public void destroy() throws Throwable {
	}

	@Override
	public IBeanFactory beanFactory() {
		return beanFactory;
	}

	@Override
	public void registerModule(IModuleContext mooduleContext) {
		// mapping symbolicName
		mappingBysymbolicName(mooduleContext);
		// mapping export packages
		mappingExportPackages(mooduleContext);
	}

	// @Override
	public IModuleContext getModule(String symbolicName, String version) {
		TreeSet<IModuleContext> set = symbolicName2modules.get(symbolicName);
		if (set == null || set.isEmpty())
			return null;
		if (StrKit.isBlank(version))
			return set.iterator().next();
		for (IModuleContext mContext : set) {
			if (version.equalsIgnoreCase(mContext.getVersion()))
				return mContext;
		}
		return null;
	}

	public IModuleContext getModuleByExportPackage(String packageName,
			String version) {
		TreeSet<IModuleContext> set = exportPackage2Modules.get(packageName);
		if (set == null || set.isEmpty())
			return null;
		if (StrKit.isBlank(version))
			return set.iterator().next();
		for (IModuleContext mContext : set) {
			if (version.equalsIgnoreCase(mContext.getVersion()))
				return mContext;
		}
		return null;
	}

	/**
	 * mapping export packages
	 * 
	 * @param mContext
	 */
	private void mappingExportPackages(IModuleContext mContext) {
		Set<String> exportPackages = mContext.getExportPackages();
		for (String exportPkg : exportPackages) {
			TreeSet<IModuleContext> set = exportPackage2Modules.get(exportPkg);
			if (set == null) {
				set = new TreeSet<IModuleContext>(mVerReverseComparator);
				exportPackage2Modules.put(exportPkg, set);
			}
			set.add(mContext);
		}
	}

	/**
	 * mapping symbolicName
	 * 
	 * @param mContext
	 */
	private void mappingBysymbolicName(IModuleContext mContext) {
		String symbolicName = mContext.getSymbolicName();
		TreeSet<IModuleContext> set = symbolicName2modules.get(symbolicName);
		if (set == null) {
			set = new TreeSet<IModuleContext>(mVerReverseComparator);
			symbolicName2modules.put(symbolicName, set);
		}
		set.add(mContext);
	}

	// @Override
	public void addClassHandler(ClassHandler classHandler) {
		classHandlers.add(classHandler);
	}

	public HashSet<ClassHandler> getClassHandlers() {
		return classHandlers;
	}

	private Comparator<IModuleContext> getModuleContextVersionComparator() {
		return new Comparator<IModuleContext>() {

			public int compare(IModuleContext o1, IModuleContext o2) {
				String[] versionArray1 = StrKit.split(
						StrKit.blankDefault(o1.getVersion(), ""), ".");
				String[] versionArray2 = StrKit.split(
						StrKit.blankDefault(o2.getVersion(), ""), ".");
				int idx = 0;
				int minLength = Math.min(versionArray1.length,
						versionArray2.length);// 取最小长度值
				int diff = 0;
				while (idx < minLength
						&& (diff = versionArray1[idx].length()
								- versionArray2[idx].length()) == 0// 先比较长度
						&& (diff = versionArray1[idx]
								.compareTo(versionArray2[idx])) == 0) {// 再比较字符
					++idx;
				}
				// 如果已经分出大小，则直接返回，如果未分出大小，则再比较位数，有子版本的为大；
				return (diff != 0) ? diff : versionArray1.length
						- versionArray2.length;
			}
		};
	}

	void stopModules() {
		Collection<TreeSet<IModuleContext>> values = symbolicName2modules.values();
		for (TreeSet<IModuleContext> set : values) {
			for (IModuleContext mContext : set) {
				try {
					mContext.stop();
				} catch (Exception e) {
					LOG.error("stop module " + mContext.getSymbolicName()
							+ " failed", e);
				}
			}
		}
	}
}
